home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / proc / procRecovery.c < prev    next >
C/C++ Source or Header  |  1990-10-09  |  11KB  |  394 lines

  1. /* 
  2.  * procRecovery.c
  3.  *
  4.  *    Routines for process migration recovery.
  5.  *
  6.  * Copyright 1988, 1989, 1990 Regents of the University of California.
  7.  * All rights reserved.
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /sprite/src/kernel/proc/RCS/procRecovery.c,v 9.4 90/09/12 13:58:25 jhh Exp $ SPRITE (Berkeley)";
  19. #endif /* not lint */
  20.  
  21. #include <sprite.h>
  22. #include <proc.h>
  23. #include <procInt.h>
  24. #include <procMigrate.h>
  25. #include <migrate.h>
  26. #include <recov.h>
  27. #include <sync.h>
  28. #include <rpc.h>
  29. #include <hash.h>
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32.  
  33. static void HostChanged _ARGS_((int hostID, ClientData clientData));
  34.  
  35. static Sync_Lock recovLock;
  36. Sync_Condition recovCondition = {0};
  37. #define LOCKPTR &recovLock
  38.  
  39. typedef struct DependInfo {
  40.     Proc_PID    processID;    /* the process ID on our host, and the
  41.                  * key into the hash table */
  42.     Proc_PID    peerProcessID;    /* the process ID on the other host. */
  43.     int        hostID;        /* the other host for the process
  44.                  * (home or remote) */
  45.     int        flags;        /* Flags (see below) */
  46. } DependInfo;
  47.  
  48. /*
  49.  * Define constants for use with migration-recovery interaction.
  50.  *
  51.  *    DEPEND_UNREACHABLE    - host was unable to receive death notice.
  52.  */
  53. #define DEPEND_UNREACHABLE 1
  54.  
  55. /*
  56.  * Flags for HostChanged.
  57.  *    HOST_CRASHED     - a host is down, or rebooted.
  58.  *    HOST_UP        - host is reachable.
  59.  */
  60. #define HOST_CRASHED 0
  61. #define HOST_UP 1
  62.  
  63. /*
  64.  * Hash tables for dependency information.
  65.  */
  66.  
  67. Hash_Table    dependHashTableStruct;
  68. Hash_Table    *dependHashTable = &dependHashTableStruct;
  69.  
  70. /*
  71.  * Define a structure for keeping track of dependencies while doing
  72.  * a hash search -- we store the key in a list and do individual hash
  73.  * lookups once the search is over.
  74.  */
  75. typedef struct {
  76.     List_Links links;        /* Pointers within list. */
  77.     Proc_PID processID;        /* Key. */
  78. } DependChain;
  79.  
  80. #define KERNEL_HASH
  81.  
  82.  
  83. /*
  84.  *----------------------------------------------------------------------
  85.  *
  86.  * ProcRecovInit --
  87.  *
  88.  *    Initialize the data structures for process migration recovery.
  89.  *
  90.  * Results:
  91.  *    None.
  92.  *
  93.  * Side effects:
  94.  *    Hash table is initialized and the recovery system is told to
  95.  *    alert us when it determines that a host has crashed.
  96.  *
  97.  *----------------------------------------------------------------------
  98.  */
  99. void
  100. ProcRecovInit()
  101. {
  102.     Hash_Init(dependHashTable, 0, HASH_ONE_WORD_KEYS);
  103.     Recov_CrashRegister(HostChanged, (ClientData) HOST_CRASHED);
  104.     Sync_LockInitDynamic(&recovLock, "Proc:recovLock");
  105. }
  106.  
  107.  
  108. /*
  109.  *----------------------------------------------------------------------
  110.  *
  111.  * HostChanged --
  112.  *
  113.  *    Kill off any migrated processes associated with a host that has
  114.  *    crashed.  Notify anyone waiting for a change in host.
  115.  *
  116.  * Results:
  117.  *    None.
  118.  *
  119.  * Side effects:
  120.  *    None.
  121.  *
  122.  *----------------------------------------------------------------------
  123.  */
  124. static ENTRY void
  125. HostChanged(hostID, clientData)
  126.     int hostID;        /* Host that has rebooted */
  127.     ClientData clientData;    /* Whether the host crashed. */
  128. {
  129.     Hash_Search            hashSearch;
  130.     register Hash_Entry        *hashEntryPtr;
  131.     DependInfo            *dependPtr;
  132.     List_Links            dependList;
  133.     DependChain            *chainPtr;
  134.     Boolean            crashed;
  135.  
  136.     LOCK_MONITOR;
  137.  
  138.     crashed = ((int) clientData) == HOST_CRASHED;
  139.     
  140.     Sync_Broadcast(&recovCondition);
  141.     Hash_StartSearch(&hashSearch);
  142.     List_Init(&dependList);
  143.     for (hashEntryPtr = Hash_Next(dependHashTable, &hashSearch);
  144.          hashEntryPtr != (Hash_Entry *) NIL;  
  145.      hashEntryPtr = Hash_Next(dependHashTable, &hashSearch)) {
  146.     dependPtr = (DependInfo *) Hash_GetValue(hashEntryPtr);
  147.     if (dependPtr->hostID == hostID) {
  148.         if (crashed && !(dependPtr->flags & DEPEND_UNREACHABLE)) {
  149.         /*
  150.          * This process still exists on our host.
  151.          */
  152.         Proc_CallFunc(Proc_DestroyMigratedProc,
  153.                   (ClientData) dependPtr->processID, 0);
  154.         } else if (crashed || (dependPtr->flags & DEPEND_UNREACHABLE)){
  155.         /*
  156.          * Either the host crashed but we already killed the
  157.          * process and just want to get rid of the hash entry,
  158.          * or it has come back and we want to notify it about
  159.          * a dead process.
  160.          */
  161.         chainPtr = (DependChain *) malloc(sizeof(DependChain));
  162.         chainPtr->processID = dependPtr->processID;
  163.         List_InitElement(&chainPtr->links);
  164.         List_Insert(&chainPtr->links, LIST_ATREAR(&dependList));
  165.         if (!crashed) {
  166.             Proc_CallFunc(ProcMigKillRemoteCopy,
  167.                   (ClientData) dependPtr->peerProcessID, 0);
  168.         }
  169.             
  170.         }  
  171.     }
  172.     }
  173.     /*
  174.      * Now clean up the list of dependencies to do Hash_Deletes.
  175.      */
  176.     while (!List_IsEmpty(&dependList)) {
  177.     chainPtr = (DependChain *) List_First(&dependList);
  178.     List_Remove((List_Links *) chainPtr);
  179. #ifdef KERNEL_HASH
  180.     hashEntryPtr = Hash_LookOnly(dependHashTable,
  181.                      (Address) chainPtr->processID);
  182.     if (hashEntryPtr != (Hash_Entry *) NIL) {
  183. #else KERNEL_HASH
  184.         hashEntryPtr = Hash_FindEntry(dependHashTable,
  185.                       (Address) chainPtr->processID);
  186.     if (hashEntryPtr != (Hash_Entry *) NULL) {
  187. #endif                /* KERNEL_HASH */
  188.         dependPtr = (DependInfo *) Hash_GetValue(hashEntryPtr);
  189. #ifdef KERNEL_HASH
  190.         Hash_Delete(dependHashTable, hashEntryPtr);
  191. #else KERNEL_HASH
  192.         Hash_DeleteEntry(dependHashTable, hashEntryPtr);
  193. #endif                /* KERNEL_HASH */
  194.         Recov_RebootUnRegister(dependPtr->hostID, HostChanged,
  195.                    clientData);
  196.         free ((Address) dependPtr);
  197.     }
  198.     free((char *) chainPtr);
  199.     }
  200.     UNLOCK_MONITOR;
  201. }
  202.  
  203.  
  204. /*
  205.  *----------------------------------------------------------------------
  206.  *
  207.  * ProcMigAddDependency --
  208.  *
  209.  *    Note a dependency of a process on a remote machine.
  210.  *
  211.  * Results:
  212.  *    None.
  213.  *
  214.  * Side effects:
  215.  *    Memory is allocated for a structure to be put in the hash table.
  216.  *
  217.  *----------------------------------------------------------------------
  218.  */
  219. ENTRY void
  220. ProcMigAddDependency(processID, peerProcessID)
  221.     Proc_PID processID;        /* process that depends on the host */
  222.     Proc_PID peerProcessID;    /* process on the other host */
  223. {
  224.     DependInfo *dependPtr;
  225.     Hash_Entry *hashEntryPtr;
  226.     Boolean new;
  227.     
  228.     LOCK_MONITOR;
  229.  
  230.  
  231.     dependPtr = (DependInfo *) malloc(sizeof (DependInfo));
  232.  
  233.     dependPtr->processID = processID;
  234.     dependPtr->peerProcessID = peerProcessID;
  235.     dependPtr->hostID = Proc_GetHostID(peerProcessID);
  236.     dependPtr->flags = 0;
  237. #ifdef KERNEL_HASH
  238.     hashEntryPtr = Hash_Find(dependHashTable, (Address) processID);
  239.     new = (hashEntryPtr->value == (Address) NIL);
  240. #else KERNEL_HASH
  241.     hashEntryPtr = Hash_CreateEntry(dependHashTable, (Address) processID, &new);
  242. #endif /* KERNEL_HASH */
  243.     if (!new) {
  244.     if (proc_MigDebugLevel > 0) {
  245.         if (proc_MigDebugLevel > 4) {
  246.         panic("ProcMigAddDependency: process %x already registered.\n",
  247.               processID);
  248.         } else {
  249.         printf(
  250.         "%s ProcMigAddDependency: process %x already registered.\n",
  251.               "Warning:", processID);
  252.         }
  253.     }
  254.     UNLOCK_MONITOR;
  255.     return;
  256.     }
  257.     Hash_SetValue(hashEntryPtr, (ClientData) dependPtr);
  258.     Recov_RebootRegister(dependPtr->hostID, HostChanged, (ClientData) HOST_UP);
  259.     UNLOCK_MONITOR;
  260. }
  261.  
  262.  
  263.  
  264. /*
  265.  *----------------------------------------------------------------------
  266.  *
  267.  * ProcMigRemoveDependency --
  268.  *
  269.  *    Remove a process from the table of dependencies on remote machines.
  270.  *    If the other host wasn't notified, defer the removal until the other
  271.  *     host is known to be down or rebooted, and notify the other host
  272.  *    of the death of the process if it should come back.  After this
  273.  *    routine is called, the routines in this file are responsible for
  274.  *    eventually getting rid of the dependency (e.g., the caller
  275.  *     won't call again).
  276.  *
  277.  * Results:
  278.  *    None.
  279.  *
  280.  * Side effects:
  281.  *    The corresponding entry for the process is removed from the
  282.  *    hash table and freed, or flagged for future removal.
  283.  *
  284.  *----------------------------------------------------------------------
  285.  */
  286. ENTRY void
  287. ProcMigRemoveDependency(processID, notified)
  288.     Proc_PID processID;        /* process to remove */
  289.     Boolean notified;        /* Whether other host was notified of death. */
  290. {
  291.     DependInfo *dependPtr;
  292.     Hash_Entry *hashEntryPtr;
  293.     
  294.     LOCK_MONITOR;
  295.  
  296. #ifdef KERNEL_HASH
  297.     hashEntryPtr = Hash_LookOnly(dependHashTable, (Address) processID);
  298.     if (hashEntryPtr == (Hash_Entry *) NIL) {
  299. #else KERNEL_HASH
  300.     hashEntryPtr = Hash_FindEntry(dependHashTable, (Address) processID);
  301.     if (hashEntryPtr == (Hash_Entry *) NULL) {
  302. #endif /* KERNEL_HASH */
  303. #ifdef notdef
  304.     /*
  305.      * (We're not going to care if it's already been removed because we
  306.      * are called to get rid of processIDs that may already have been
  307.      * removed, and we're just making doubly sure.)
  308.      */
  309.     if (proc_MigDebugLevel > 0) {
  310.         if (proc_MigDebugLevel > 4) {
  311.         panic("ProcMigRemoveDependency: process %x not registered.\n",
  312.               processID);
  313.         } else {
  314.         printf(
  315.             "%s ProcMigRemoveDependency: process %x not registered.\n",
  316.             "Warning:", processID);
  317.         }
  318.     }
  319. #endif /* notdef */
  320.     UNLOCK_MONITOR;
  321.     return;
  322.     }
  323.     dependPtr = (DependInfo *) Hash_GetValue(hashEntryPtr);
  324.     if (!notified) {
  325.     dependPtr->flags |= DEPEND_UNREACHABLE;
  326.     UNLOCK_MONITOR;
  327.     return;
  328.     }
  329. #ifdef KERNEL_HASH
  330.     Hash_Delete(dependHashTable, hashEntryPtr);
  331. #else KERNEL_HASH
  332.     Hash_DeleteEntry(dependHashTable, hashEntryPtr);
  333. #endif /* KERNEL_HASH */
  334.     Recov_RebootUnRegister(dependPtr->hostID, HostChanged,
  335.                (ClientData) HOST_UP);
  336.     free ((Address) dependPtr);
  337.     UNLOCK_MONITOR;
  338. }
  339.  
  340.  
  341.  
  342.  
  343. /*
  344.  *----------------------------------------------------------------------
  345.  *
  346.  * Proc_WaitForHost --
  347.  *
  348.  *    Wait until a host has fully crashed, come back, or rebooted.
  349.  *    This will return a failure code if the host crashed.
  350.  *
  351.  * Results:
  352.  *    SUCCESS - the host is useable again.
  353.  *    NET_UNREACHABLE_HOST - the host crashed.
  354.  *    GEN_ABORTED_BY_SIGNAL - a signal was received while waiting.
  355.  *
  356.  * Side effects:
  357.  *    Block the process if waiting for the host to return or crash.
  358.  *
  359.  *----------------------------------------------------------------------
  360.  */
  361. ENTRY ReturnStatus
  362. Proc_WaitForHost(hostID)
  363.     int hostID;
  364. {
  365.     register ReturnStatus status = SUCCESS;
  366.     int hostState;
  367.  
  368.     LOCK_MONITOR;
  369.     hostState = Recov_GetClientState(hostID);
  370.     while (hostState & RECOV_HOST_DYING) {
  371.     if (Sync_Wait(&recovCondition, TRUE)) {
  372.         status = GEN_ABORTED_BY_SIGNAL;
  373.         break;
  374.     }
  375.     hostState = Recov_GetClientState(hostID);
  376.     }
  377.     if (status == SUCCESS) {
  378.     if (hostState & (RECOV_HOST_DEAD | RECOV_HOST_BOOTING)) {
  379.         /*
  380.          * Host has crashed and is either out of touch or rebooting now.
  381.          * Cause migrated clients to get killed.
  382.          */
  383.         status = NET_UNREACHABLE_HOST;
  384.     } else if (hostState & RECOV_HOST_ALIVE) {
  385.         /*
  386.          * Host is back, so continue business as usual.
  387.          */
  388.         status = SUCCESS;
  389.     }
  390.     }
  391.     UNLOCK_MONITOR;
  392.     return(status);
  393. }
  394.